/*
** using_free_list.c for  in /home/alxevo/Documents/projets/malloc-2015-2014s-ravera_t
** 
** Made by Thibault Ravera
** Login   <ravera_t@epitech.net>
** 
** Started on  Sun Feb  5 19:13:28 2012 Thibault Ravera
** Last update Sun Feb  5 19:14:41 2012 Thibault Ravera
*/

#include	"malloc.h"

void		*search_in_free_list(size_t size)
{
  void		*tmp;

  tmp = bins[_MYLIST];
  while (tmp)
    {
      if ((MEM2CHUNK(tmp)->size & ~PINUSE) >= size &&
	  !IS_TOO_SMALL((MEM2CHUNK(tmp)->size & ~PINUSE), size))
	return (tmp);
      tmp = MEM2CHUNK(tmp)->prev;
    }
  return (NULL);
}

void		exchange_pointer_chunk(void *ptr)
{
  void		*next_chunk;
  void		*prev_chunk;

  next_chunk = MEM2CHUNK(ptr)->next;
  prev_chunk = MEM2CHUNK(ptr)->prev;
  NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->prev_size = 0;
  NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->size &= ~PINUSE;
  if (next_chunk)
    MEM2CHUNK(next_chunk)->prev = MEM2CHUNK(ptr)->prev;
  else
    bins[_MYLIST] = prev_chunk;
  if (prev_chunk)
    MEM2CHUNK(prev_chunk)->next = MEM2CHUNK(ptr)->next;
}

void		split_chunk(void *ptr, size_t size)
{
  t_header	*next_chunk;
  t_header	*current_chunk;

  current_chunk = MEM2CHUNK(ptr);
  next_chunk = MEM2CHUNK(ptr + (size));
  NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->prev_size =
    (MEM2CHUNK(ptr)->size & ~PINUSE) - size;
  NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->size |= PINUSE;
  next_chunk->size = ((current_chunk->size & ~PINUSE) - size);
  current_chunk->size = (size |= (current_chunk->size & PINUSE));
  if (current_chunk->prev)
    MEM2CHUNK(current_chunk->prev)->next = CHUNK2MEM(next_chunk);
  if (current_chunk->next)
    MEM2CHUNK(current_chunk->next)->prev = CHUNK2MEM(next_chunk);
  next_chunk->prev = current_chunk->prev;
  next_chunk->next = current_chunk->next;
  if (current_chunk->next == NULL)
    bins[_MYLIST] = CHUNK2MEM(next_chunk);
}

void		*search_in_bins(int idx)
{
  void		*head;

  if (idx >= (SIZE_ARRAY_BINS - 1))
    return (NULL);
  if (bins[idx] == NULL)
    return (NULL);
  head = bins[idx];
  bins[idx] = MEM2CHUNK(head)->prev;
  if (bins[idx])
    MEM2CHUNK(bins[idx])->next = NULL;
  MEM2CHUNK(head)->prev = NULL;
  MEM2CHUNK(head)->next = NULL;
  return (head);
}

void		*use_free_list(size_t real_size)
{
  void		*ptr;

  if ((ptr = search_in_bins(IDX(real_size))))
    return (ptr);
  if ((ptr = search_in_free_list(real_size)))
    {
      if ((MEM2CHUNK(ptr)->size & ~PINUSE) == real_size)
	exchange_pointer_chunk(ptr);
      else
	split_chunk(ptr, real_size);
      MEM2CHUNK(ptr)->next = NULL;
      MEM2CHUNK(ptr)->prev = NULL;
      return (ptr);
    }
  return (NULL);
}
